﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
using Meow.Core;

namespace Meow.Editor.Spatial;

public class Node3D
{
    public Node3D Parent { get; private set; }

    readonly HashSet<Node3D> Children = new HashSet<Node3D>(0);

    public bool AddChild(Node3D child)
    {
        if (Parent == child || child.HasChild(this))
            return false;

        Children.Add(child); 
        child.Parent = this;
        return true;
    }

    public bool HasChild(Node3D node)
    {
        if (!Children.Contains(node))
        {
            foreach (var child in Children)
                if (child.HasChild(node))
                    return true;
        }
        else
            return true;

        return false;
    }

    public Node3D[] GetChildrens() => Children.ToArray();

    public string Name;

    public Node3D FindNode(in string name)
    {
        if (name.Equals(Name))
        {
            return this;
        }

        if (Children.Any())
        {
            foreach (var child in Children)
            {
                var node = child.FindNode(name);
                if (node != null)
                {
                    return node;
                }
            }
        }

        return null;
    }

    Vector3 _position;
    Quaternion _rotation;
    Vector3 _scale;
    Matrix4x4 _transform;

    public Vector3 Position
    {
        get => _position; set
        {
            _position = value;
            _transform.M14 = _position.X;
            _transform.M24 = _position.Y;
            _transform.M34 = _position.Z;
        }
    }

    public Quaternion Rotation
    {
        get => _rotation;
        set
        {
            _rotation = value;
            NumericsExts.Create(_position, _rotation, _scale);
        }
    }
    public Vector3 Scale
    {
        get => _scale;
        set
        {
            _scale = value;
            NumericsExts.Create(_position, _rotation, _scale);
        }
    }

    public Matrix4x4 Transform
    {
        get => _transform;
        set
        {
            _transform = value;
            _transform.Decompose(out _scale, out _rotation, out _position);
        }
    }


    public Node3D()
    {
        Transform = Matrix4x4.Identity;
    }

    public Node3D(in Matrix4x4 transform)
    {
        Transform = transform;
    }



    private static Matrix4x4 GetRelativeTransform(Node3D node, Node3D ancestor)
    {
        // Get transform of node relative to ancestor.
        Matrix4x4 transform = node.Transform;
        Node3D parent = node.Parent;
        while (parent != null && parent != ancestor)
        {
            transform *= parent.Transform;
            parent = parent.Parent;
        }

        if (parent == null && ancestor != null)
            throw new ArgumentException(string.Format("Node \"{0}\" is not an ancestor of \"{1}\".", ancestor.Name, node.Name));

        return transform;
    }
}
